/* PNotify modules included in this custom build file:
brighttheme
buttons
desktop
mobile
*/
/*
PNotify 3.2.0 sciactive.com/pnotify/
(C) 2015 Hunter Perrin; Google, Inc.
license Apache-2.0
*/
/*
 * ====== PNotify ======
 *
 * http://sciactive.com/pnotify/
 *
 * Copyright 2009-2015 Hunter Perrin
 * Copyright 2015 Google, Inc.
 *
 * Licensed under Apache License, Version 2.0.
 * 	http://www.apache.org/licenses/LICENSE-2.0
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as a module.
    define('pnotify', ['jquery'], function($){
      return factory($, root);
    });
  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
    // CommonJS
    module.exports = factory(require('jquery'), global || root);
  } else {
    // Browser globals
    root.PNotify = factory(root.jQuery, root);
  }
}(typeof window !== "undefined" ? window : this, function($, root){
var init = function(root){
  var default_stack = {
    dir1: "down",
    dir2: "left",
    push: "bottom",
    spacing1: 36,
    spacing2: 36,
    context: $("body"),
    modal: false
  };
  var posTimer, // Position all timer.
    body,
    jwindow = $(root);
  // Set global variables.
  var do_when_ready = function(){
    body = $("body");
    PNotify.prototype.options.stack.context = body;
    jwindow = $(root);
    // Reposition the notices when the window resizes.
    jwindow.bind('resize', function(){
      if (posTimer) {
        clearTimeout(posTimer);
      }
      posTimer = setTimeout(function(){
        PNotify.positionAll(true);
      }, 10);
    });
  };
  var createStackOverlay = function(stack) {
    var overlay = $("<div />", {"class": "ui-pnotify-modal-overlay"});
    overlay.prependTo(stack.context);
    if (stack.overlay_close) {
      // Close the notices on overlay click.
      overlay.click(function(){
        PNotify.removeStack(stack);
      });
    }
    return overlay;
  };
  var PNotify = function(options){
    // === Class Variables ===
    this.state = "initializing"; // The state can be "initializing", "opening", "open", "closing", and "closed".
    this.timer = null; // Auto close timer.
    this.animTimer = null; // Animation timer.
    this.styles = null;
    this.elem = null;
    this.container = null;
    this.title_container = null;
    this.text_container = null;
    this.animating = false; // Stores what is currently being animated (in or out).
    this.timerHide = false; // Stores whether the notice was hidden by a timer.

    this.parseOptions(options);
    this.init();
  };
  $.extend(PNotify.prototype, {
    // The current version of PNotify.
    version: "3.2.0",

    // === Options ===

    // Options defaults.
    options: {
      // The notice's title.
      title: false,
      // Whether to escape the content of the title. (Not allow HTML.)
      title_escape: false,
      // The notice's text.
      text: false,
      // Whether to escape the content of the text. (Not allow HTML.)
      text_escape: false,
      // What styling classes to use. (Can be either "brighttheme", "bootstrap3", or "fontawesome".)
      styling: "brighttheme",
      // Additional classes to be added to the notice. (For custom styling.)
      addclass: "",
      // Class to be added to the notice for corner styling.
      cornerclass: "",
      // Display the notice when it is created.
      auto_display: true,
      // Width of the notice.
      width: "300px",
      // Minimum height of the notice. It will expand to fit content.
      min_height: "16px",
      // Type of the notice. "notice", "info", "success", or "error".
      type: "notice",
      // Set icon to true to use the default icon for the selected
      // style/type, false for no icon, or a string for your own icon class.
      icon: true,
      // The animation to use when displaying and hiding the notice. "none"
      // and "fade" are supported through CSS. Others are supported
      // through the Animate module and Animate.css.
      animation: "fade",
      // Speed at which the notice animates in and out. "slow", "normal",
      // or "fast". Respectively, 400ms, 250ms, 100ms.
      animate_speed: "normal",
      // Display a drop shadow.
      shadow: true,
      // After a delay, remove the notice.
      hide: true,
      // Delay in milliseconds before the notice is removed.
      delay: 8000,
      // Reset the hide timer if the mouse moves over the notice.
      mouse_reset: true,
      // Remove the notice's elements from the DOM after it is removed.
      remove: true,
      // Change new lines to br tags.
      insert_brs: true,
      // Whether to remove the notice from the global array when it is closed.
      destroy: true,
      // The stack on which the notices will be placed. Also controls the
      // direction the notices stack.
      stack: default_stack
    },

    // === Modules ===

    // This object holds all the PNotify modules. They are used to provide
    // additional functionality.
    modules: {},
    // This runs an event on all the modules.
    runModules: function(event, arg){
      var curArg;
      for (var module in this.modules) {
        curArg = ((typeof arg === "object" && module in arg) ? arg[module] : arg);
        if (typeof this.modules[module][event] === 'function') {
          this.modules[module].notice = this;
          this.modules[module].options = typeof this.options[module] === 'object' ? this.options[module] : {};
          this.modules[module][event](this, typeof this.options[module] === 'object' ? this.options[module] : {}, curArg);
        }
      }
    },

    // === Events ===

    init: function(){
      var that = this;

      // First and foremost, we don't want our module objects all referencing the prototype.
      this.modules = {};
      $.extend(true, this.modules, PNotify.prototype.modules);

      // Get our styling object.
      if (typeof this.options.styling === "object") {
        this.styles = this.options.styling;
      } else {
        this.styles = PNotify.styling[this.options.styling];
      }

      // Create our widget.
      // Stop animation, reset the removal timer when the user mouses over.
      this.elem = $("<div />", {
        "class": "ui-pnotify "+this.options.addclass,
        "css": {"display": "none"},
        "aria-live": "assertive",
        "aria-role": "alertdialog",
        "mouseenter": function(e){
          if (that.options.mouse_reset && that.animating === "out") {
            if (!that.timerHide) {
              return;
            }
            that.cancelRemove();
          }
          // Stop the close timer.
          if (that.options.hide && that.options.mouse_reset) {
            that.cancelRemove();
          }
        },
        "mouseleave": function(e){
          // Start the close timer.
          if (that.options.hide && that.options.mouse_reset && that.animating !== "out") {
            that.queueRemove();
          }
          PNotify.positionAll();
        }
      });
      // Maybe we need to fade in/out.
      if (this.options.animation === "fade") {
        this.elem.addClass("ui-pnotify-fade-"+this.options.animate_speed);
      }
      // Create a container for the notice contents.
      this.container = $("<div />", {
        "class": this.styles.container+" ui-pnotify-container "+(this.options.type === "error" ? this.styles.error : (this.options.type === "info" ? this.styles.info : (this.options.type === "success" ? this.styles.success : this.styles.notice))),
        "role": "alert"
      }).appendTo(this.elem);
      if (this.options.cornerclass !== "") {
        this.container.removeClass("ui-corner-all").addClass(this.options.cornerclass);
      }
      // Create a drop shadow.
      if (this.options.shadow) {
        this.container.addClass("ui-pnotify-shadow");
      }


      // Add the appropriate icon.
      if (this.options.icon !== false) {
        $("<div />", {"class": "ui-pnotify-icon"})
        .append($("<span />", {"class": this.options.icon === true ? (this.options.type === "error" ? this.styles.error_icon : (this.options.type === "info" ? this.styles.info_icon : (this.options.type === "success" ? this.styles.success_icon : this.styles.notice_icon))) : this.options.icon}))
        .prependTo(this.container);
      }

      // Add a title.
      this.title_container = $("<h4 />", {
        "class": "ui-pnotify-title"
      })
      .appendTo(this.container);
      if (this.options.title === false) {
        this.title_container.hide();
      } else if (this.options.title_escape) {
        this.title_container.text(this.options.title);
      } else {
        this.title_container.html(this.options.title);
      }

      // Add text.
      this.text_container = $("<div />", {
        "class": "ui-pnotify-text",
        "aria-role": "alert"
      })
      .appendTo(this.container);
      if (this.options.text === false) {
        this.text_container.hide();
      } else if (this.options.text_escape) {
        this.text_container.text(this.options.text);
      } else {
        this.text_container.html(this.options.insert_brs ? String(this.options.text).replace(/\n/g, "<br />") : this.options.text);
      }

      // Set width and min height.
      if (typeof this.options.width === "string") {
        this.elem.css("width", this.options.width);
      }
      if (typeof this.options.min_height === "string") {
        this.container.css("min-height", this.options.min_height);
      }


      // Add the notice to the notice array.
      if (this.options.stack.push === "top") {
        PNotify.notices = $.merge([this], PNotify.notices);
      } else {
        PNotify.notices = $.merge(PNotify.notices, [this]);
      }
      // Now position all the notices if they are to push to the top.
      if (this.options.stack.push === "top") {
        this.queuePosition(false, 1);
      }


      // Mark the stack so it won't animate the new notice.
      this.options.stack.animation = false;

      // Run the modules.
      this.runModules('init');

      // We're now initialized, but haven't been opened yet.
      this.state = "closed";

      // Display the notice.
      if (this.options.auto_display) {
        this.open();
      }
      return this;
    },

    // This function is for updating the notice.
    update: function(options){
      // Save old options.
      var oldOpts = this.options;
      // Then update to the new options.
      this.parseOptions(oldOpts, options);
      // Maybe we need to fade in/out.
      this.elem.removeClass("ui-pnotify-fade-slow ui-pnotify-fade-normal ui-pnotify-fade-fast");
      if (this.options.animation === "fade") {
        this.elem.addClass("ui-pnotify-fade-"+this.options.animate_speed);
      }
      // Update the corner class.
      if (this.options.cornerclass !== oldOpts.cornerclass) {
        this.container.removeClass("ui-corner-all "+oldOpts.cornerclass).addClass(this.options.cornerclass);
      }
      // Update the shadow.
      if (this.options.shadow !== oldOpts.shadow) {
        if (this.options.shadow) {
          this.container.addClass("ui-pnotify-shadow");
        } else {
          this.container.removeClass("ui-pnotify-shadow");
        }
      }
      // Update the additional classes.
      if (this.options.addclass === false) {
        this.elem.removeClass(oldOpts.addclass);
      } else if (this.options.addclass !== oldOpts.addclass) {
        this.elem.removeClass(oldOpts.addclass).addClass(this.options.addclass);
      }
      // Update the title.
      if (this.options.title === false) {
        this.title_container.slideUp("fast");
      } else if (this.options.title !== oldOpts.title) {
        if (this.options.title_escape) {
          this.title_container.text(this.options.title);
        } else {
          this.title_container.html(this.options.title);
        }
        if (oldOpts.title === false) {
          this.title_container.slideDown(200);
        }
      }
      // Update the text.
      if (this.options.text === false) {
        this.text_container.slideUp("fast");
      } else if (this.options.text !== oldOpts.text) {
        if (this.options.text_escape) {
          this.text_container.text(this.options.text);
        } else {
          this.text_container.html(this.options.insert_brs ? String(this.options.text).replace(/\n/g, "<br />") : this.options.text);
        }
        if (oldOpts.text === false) {
          this.text_container.slideDown(200);
        }
      }
      // Change the notice type.
      if (this.options.type !== oldOpts.type) {
        this.container.removeClass(
          this.styles.error+" "+this.styles.notice+" "+this.styles.success+" "+this.styles.info
        ).addClass(this.options.type === "error" ?
          this.styles.error :
          (this.options.type === "info" ?
            this.styles.info :
            (this.options.type === "success" ?
              this.styles.success :
              this.styles.notice
            )
          )
        );
      }
      if (this.options.icon !== oldOpts.icon || (this.options.icon === true && this.options.type !== oldOpts.type)) {
        // Remove any old icon.
        this.container.find("div.ui-pnotify-icon").remove();
        if (this.options.icon !== false) {
          // Build the new icon.
          $("<div />", {"class": "ui-pnotify-icon"})
          .append($("<span />", {"class": this.options.icon === true ? (this.options.type === "error" ? this.styles.error_icon : (this.options.type === "info" ? this.styles.info_icon : (this.options.type === "success" ? this.styles.success_icon : this.styles.notice_icon))) : this.options.icon}))
          .prependTo(this.container);
        }
      }
      // Update the width.
      if (this.options.width !== oldOpts.width) {
        this.elem.animate({width: this.options.width});
      }
      // Update the minimum height.
      if (this.options.min_height !== oldOpts.min_height) {
        this.container.animate({minHeight: this.options.min_height});
      }
      // Update the timed hiding.
      if (!this.options.hide) {
        this.cancelRemove();
      } else if (!oldOpts.hide) {
        this.queueRemove();
      }
      this.queuePosition(true);

      // Run the modules.
      this.runModules('update', oldOpts);
      return this;
    },

    // Display the notice.
    open: function(){
      this.state = "opening";
      // Run the modules.
      this.runModules('beforeOpen');

      var that = this;
      // If the notice is not in the DOM, append it.
      if (!this.elem.parent().length) {
        this.elem.appendTo(this.options.stack.context ? this.options.stack.context : body);
      }
      // Try to put it in the right position.
      if (this.options.stack.push !== "top") {
        this.position(true);
      }
      this.animateIn(function(){
        that.queuePosition(true);

        // Now set it to hide.
        if (that.options.hide) {
          that.queueRemove();
        }

        that.state = "open";

        // Run the modules.
        that.runModules('afterOpen');
      });

      return this;
    },

    // Remove the notice.
    remove: function(timer_hide) {
      this.state = "closing";
      this.timerHide = !!timer_hide; // Make sure it's a boolean.
      // Run the modules.
      this.runModules('beforeClose');

      var that = this;
      if (this.timer) {
        root.clearTimeout(this.timer);
        this.timer = null;
      }
      this.animateOut(function(){
        that.state = "closed";
        // Run the modules.
        that.runModules('afterClose');
        that.queuePosition(true);
        // If we're supposed to remove the notice from the DOM, do it.
        if (that.options.remove) {
          that.elem.detach();
        }
        // Run the modules.
        that.runModules('beforeDestroy');
        // Remove object from PNotify.notices to prevent memory leak (issue #49)
        // unless destroy is off
        if (that.options.destroy) {
          if (PNotify.notices !== null) {
            var idx = $.inArray(that, PNotify.notices);
            if (idx !== -1) {
              PNotify.notices.splice(idx,1);
            }
          }
        }
        // Run the modules.
        that.runModules('afterDestroy');
      });

      return this;
    },

    // === Class Methods ===

    // Get the DOM element.
    get: function(){
      return this.elem;
    },

    // Put all the options in the right places.
    parseOptions: function(options, moreOptions){
      this.options = $.extend(true, {}, PNotify.prototype.options);
      // This is the only thing that *should* be copied by reference.
      this.options.stack = PNotify.prototype.options.stack;
      var optArray = [options, moreOptions], curOpts;
      for (var curIndex=0; curIndex < optArray.length; curIndex++) {
        curOpts = optArray[curIndex];
        if (typeof curOpts === "undefined") {
          break;
        }
        if (typeof curOpts !== 'object') {
          this.options.text = curOpts;
        } else {
          for (var option in curOpts) {
            if (this.modules[option]) {
              // Avoid overwriting module defaults.
              $.extend(true, this.options[option], curOpts[option]);
            } else {
              this.options[option] = curOpts[option];
            }
          }
        }
      }
    },

    // Animate the notice in.
    animateIn: function(callback){
      // Declare that the notice is animating in.
      this.animating = "in";
      var that = this;
      var finished = function(){
        if (that.animTimer) {
          clearTimeout(that.animTimer);
        }
        if (that.animating !== "in") {
          return;
        }
        if (that.elem.is(":visible")) {
          if (callback) {
            callback.call();
          }
          // Declare that the notice has completed animating.
          that.animating = false;
        } else {
          that.animTimer = setTimeout(finished, 40);
        }
      };

      if (this.options.animation === "fade") {
        this.elem.one('webkitTransitionEnd mozTransitionEnd MSTransitionEnd oTransitionEnd transitionend', finished).addClass("ui-pnotify-in");
        this.elem.css("opacity"); // This line is necessary for some reason. Some notices don't fade without it.
        this.elem.addClass("ui-pnotify-fade-in");
        // Just in case the event doesn't fire, call it after 650 ms.
        this.animTimer = setTimeout(finished, 650);
      } else {
        this.elem.addClass("ui-pnotify-in");
        finished();
      }
    },

    // Animate the notice out.
    animateOut: function(callback){
      // Declare that the notice is animating out.
      this.animating = "out";
      var that = this;
      var finished = function(){
        if (that.animTimer) {
          clearTimeout(that.animTimer);
        }
        if (that.animating !== "out") {
          return;
        }
        if (that.elem.css("opacity") == "0" || !that.elem.is(":visible")) {
          that.elem.removeClass("ui-pnotify-in");
          if (that.options.stack.overlay) {
            // Go through the modal stack to see if any are left open.
            // TODO: Rewrite this cause it sucks.
            var stillOpen = false;
            $.each(PNotify.notices, function(i, notice){
              if (notice != that && notice.options.stack === that.options.stack && notice.state != "closed") {
                stillOpen = true;
              }
            });
            if (!stillOpen) {
              that.options.stack.overlay.hide();
            }
          }
          if (callback) {
            callback.call();
          }
          // Declare that the notice has completed animating.
          that.animating = false;
        } else {
          // In case this was called before the notice finished animating.
          that.animTimer = setTimeout(finished, 40);
        }
      };

      if (this.options.animation === "fade") {
        this.elem.one('webkitTransitionEnd mozTransitionEnd MSTransitionEnd oTransitionEnd transitionend', finished).removeClass("ui-pnotify-fade-in");
        // Just in case the event doesn't fire, call it after 650 ms.
        this.animTimer = setTimeout(finished, 650);
      } else {
        this.elem.removeClass("ui-pnotify-in");
        finished();
      }
    },

    // Position the notice. dont_skip_hidden causes the notice to
    // position even if it's not visible.
    position: function(dontSkipHidden){
      // Get the notice's stack.
      var stack = this.options.stack,
        elem = this.elem;
      if (typeof stack.context === "undefined") {
        stack.context = body;
      }
      if (!stack) {
        return;
      }
      if (typeof stack.nextpos1 !== "number") {
        stack.nextpos1 = stack.firstpos1;
      }
      if (typeof stack.nextpos2 !== "number") {
        stack.nextpos2 = stack.firstpos2;
      }
      if (typeof stack.addpos2 !== "number") {
        stack.addpos2 = 0;
      }
      var hidden = !elem.hasClass("ui-pnotify-in");
      // Skip this notice if it's not shown.
      if (!hidden || dontSkipHidden) {
        if (stack.modal) {
          if (stack.overlay) {
            stack.overlay.show();
          } else {
            stack.overlay = createStackOverlay(stack);
          }
        }
        // Add animate class by default.
        elem.addClass("ui-pnotify-move");
        var curpos1, curpos2;
        // Calculate the current pos1 value.
        var csspos1;
        switch (stack.dir1) {
          case "down":
            csspos1 = "top";
            break;
          case "up":
            csspos1 = "bottom";
            break;
          case "left":
            csspos1 = "right";
            break;
          case "right":
            csspos1 = "left";
            break;
        }
        curpos1 = parseInt(elem.css(csspos1).replace(/(?:\..*|[^0-9.])/g, ''));
        if (isNaN(curpos1)) {
          curpos1 = 0;
        }
        // Remember the first pos1, so the first visible notice goes there.
        if (typeof stack.firstpos1 === "undefined" && !hidden) {
          stack.firstpos1 = curpos1;
          stack.nextpos1 = stack.firstpos1;
        }
        // Calculate the current pos2 value.
        var csspos2;
        switch (stack.dir2) {
          case "down":
            csspos2 = "top";
            break;
          case "up":
            csspos2 = "bottom";
            break;
          case "left":
            csspos2 = "right";
            break;
          case "right":
            csspos2 = "left";
            break;
        }
        curpos2 = parseInt(elem.css(csspos2).replace(/(?:\..*|[^0-9.])/g, ''));
        if (isNaN(curpos2)) {
          curpos2 = 0;
        }
        // Remember the first pos2, so the first visible notice goes there.
        if (typeof stack.firstpos2 === "undefined" && !hidden) {
          stack.firstpos2 = curpos2;
          stack.nextpos2 = stack.firstpos2;
        }
        // Check that it's not beyond the viewport edge.
        if (
            (stack.dir1 === "down" && stack.nextpos1 + elem.height() > (stack.context.is(body) ? jwindow.height() : stack.context.prop('scrollHeight')) ) ||
            (stack.dir1 === "up" && stack.nextpos1 + elem.height() > (stack.context.is(body) ? jwindow.height() : stack.context.prop('scrollHeight')) ) ||
            (stack.dir1 === "left" && stack.nextpos1 + elem.width() > (stack.context.is(body) ? jwindow.width() : stack.context.prop('scrollWidth')) ) ||
            (stack.dir1 === "right" && stack.nextpos1 + elem.width() > (stack.context.is(body) ? jwindow.width() : stack.context.prop('scrollWidth')) )
          ) {
          // If it is, it needs to go back to the first pos1, and over on pos2.
          stack.nextpos1 = stack.firstpos1;
          stack.nextpos2 += stack.addpos2 + (typeof stack.spacing2 === "undefined" ? 25 : stack.spacing2);
          stack.addpos2 = 0;
        }
        if (typeof stack.nextpos2 === "number") {
          if (!stack.animation) {
            elem.removeClass("ui-pnotify-move");
            elem.css(csspos2, stack.nextpos2+"px");
            elem.css(csspos2);
            elem.addClass("ui-pnotify-move");
          } else {
            elem.css(csspos2, stack.nextpos2+"px");
          }
        }
        // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row.
        switch (stack.dir2) {
          case "down":
          case "up":
            if (elem.outerHeight(true) > stack.addpos2) {
              stack.addpos2 = elem.height();
            }
            break;
          case "left":
          case "right":
            if (elem.outerWidth(true) > stack.addpos2) {
              stack.addpos2 = elem.width();
            }
            break;
        }
        // Move the notice on dir1.
        if (typeof stack.nextpos1 === "number") {
          if (!stack.animation) {
            elem.removeClass("ui-pnotify-move");
            elem.css(csspos1, stack.nextpos1+"px");
            elem.css(csspos1);
            elem.addClass("ui-pnotify-move");
          } else {
            elem.css(csspos1, stack.nextpos1+"px");
          }
        }
        // Calculate the next dir1 position.
        switch (stack.dir1) {
          case "down":
          case "up":
            stack.nextpos1 += elem.height() + (typeof stack.spacing1 === "undefined" ? 25 : stack.spacing1);
            break;
          case "left":
          case "right":
            stack.nextpos1 += elem.width() + (typeof stack.spacing1 === "undefined" ? 25 : stack.spacing1);
            break;
        }
      }
      return this;
    },
    // Queue the position all function so it doesn't run repeatedly and
    // use up resources.
    queuePosition: function(animate, milliseconds){
      if (posTimer) {
        clearTimeout(posTimer);
      }
      if (!milliseconds) {
        milliseconds = 10;
      }
      posTimer = setTimeout(function(){
        PNotify.positionAll(animate);
      }, milliseconds);
      return this;
    },


    // Cancel any pending removal timer.
    cancelRemove: function(){
      if (this.timer) {
        root.clearTimeout(this.timer);
      }
      if (this.animTimer) {
        root.clearTimeout(this.animTimer);
      }
      if (this.state === "closing") {
        // If it's animating out, stop it.
        this.state = "open";
        this.animating = false;
        this.elem.addClass("ui-pnotify-in");
        if (this.options.animation === "fade") {
          this.elem.addClass("ui-pnotify-fade-in");
        }
      }
      return this;
    },
    // Queue a removal timer.
    queueRemove: function(){
      var that = this;
      // Cancel any current removal timer.
      this.cancelRemove();
      this.timer = root.setTimeout(function(){
        that.remove(true);
      }, (isNaN(this.options.delay) ? 0 : this.options.delay));
      return this;
    }
  });
  // These functions affect all notices.
  $.extend(PNotify, {
    // This holds all the notices.
    notices: [],
    reload: init,
    removeAll: function(){
      $.each(PNotify.notices, function(i, notice){
        if (notice.remove) {
          notice.remove(false);
        }
      });
    },
    removeStack: function(stack){
      $.each(PNotify.notices, function(i, notice){
        if (notice.remove && notice.options.stack === stack) {
          notice.remove(false);
        }
      });
    },
    positionAll: function(animate){
      // This timer is used for queueing this function so it doesn't run
      // repeatedly.
      if (posTimer) {
        clearTimeout(posTimer);
      }
      posTimer = null;
      // Reset the next position data.
      if (PNotify.notices && PNotify.notices.length) {
        $.each(PNotify.notices, function(i, notice){
          var s = notice.options.stack;
          if (!s) {
            return;
          }
          if (s.overlay) {
            s.overlay.hide();
          }
          s.nextpos1 = s.firstpos1;
          s.nextpos2 = s.firstpos2;
          s.addpos2 = 0;
          s.animation = animate;
        });
        $.each(PNotify.notices, function(i, notice){
          notice.position();
        });
      } else {
        var s = PNotify.prototype.options.stack;
        if (s) {
          delete s.nextpos1;
          delete s.nextpos2;
        }
      }
    },
    styling: {
      brighttheme: {
        // Bright Theme doesn't require any UI libraries.
        container: "brighttheme",
        notice: "brighttheme-notice",
        notice_icon: "brighttheme-icon-notice",
        info: "brighttheme-info",
        info_icon: "brighttheme-icon-info",
        success: "brighttheme-success",
        success_icon: "brighttheme-icon-success",
        error: "brighttheme-error",
        error_icon: "brighttheme-icon-error"
      },
      bootstrap3: {
        container: "alert",
        notice: "alert-warning",
        notice_icon: "glyphicon glyphicon-exclamation-sign",
        info: "alert-info",
        info_icon: "glyphicon glyphicon-info-sign",
        success: "alert-success",
        success_icon: "glyphicon glyphicon-ok-sign",
        error: "alert-danger",
        error_icon: "glyphicon glyphicon-warning-sign"
      }
    }
  });
  /*
   * uses icons from http://fontawesome.io/
   * version 4.0.3
   */
  PNotify.styling.fontawesome = $.extend({}, PNotify.styling.bootstrap3);
  $.extend(PNotify.styling.fontawesome, {
    notice_icon: "fa fa-exclamation-circle",
    info_icon: "fa fa-info",
    success_icon: "fa fa-check",
    error_icon: "fa fa-warning"
  });

  if (root.document.body) {
    do_when_ready();
  } else {
    $(do_when_ready);
  }
  return PNotify;
};
return init(root);
}));

// Buttons
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as a module.
    define('pnotify.buttons', ['jquery', 'pnotify'], factory);
  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
    // CommonJS
    module.exports = factory(require('jquery'), require('./pnotify'));
  } else {
    // Browser globals
    factory(root.jQuery, root.PNotify);
  }
}(typeof window !== "undefined" ? window : this, function($, PNotify){
  PNotify.prototype.options.buttons = {
    // Provide a button for the user to manually close the notice.
    closer: true,
    // Only show the closer button on hover.
    closer_hover: true,
    // Provide a button for the user to manually stick the notice.
    sticker: true,
    // Only show the sticker button on hover.
    sticker_hover: true,
    // Show the buttons even when the nonblock module is in use.
    show_on_nonblock: false,
    // The various displayed text, helps facilitating internationalization.
    labels: {
      close: "Close",
      stick: "Stick",
      unstick: "Unstick"
    },
    // The classes to use for button icons. Leave them null to use the classes from the styling you're using.
    classes: {
      closer: null,
      pin_up: null,
      pin_down: null
    }
  };
  PNotify.prototype.modules.buttons = {
    init: function(notice, options){
      var that = this;
      notice.elem.on({
        "mouseenter": function(e){
          // Show the buttons.
          if (that.options.sticker && (!(notice.options.nonblock && notice.options.nonblock.nonblock) || that.options.show_on_nonblock)) {
            that.sticker.trigger("pnotify:buttons:toggleStick").css("visibility", "visible");
          }
          if (that.options.closer && (!(notice.options.nonblock && notice.options.nonblock.nonblock) || that.options.show_on_nonblock)) {
            that.closer.css("visibility", "visible");
          }
        },
        "mouseleave": function(e){
          // Hide the buttons.
          if (that.options.sticker_hover) {
            that.sticker.css("visibility", "hidden");
          }
          if (that.options.closer_hover) {
            that.closer.css("visibility", "hidden");
          }
        }
      });

      // Provide a button to stick the notice.
      this.sticker = $("<div />", {
        "class": "ui-pnotify-sticker",
        "aria-role": "button",
        "aria-pressed": notice.options.hide ? "false" : "true",
        "tabindex": "0",
        "title": notice.options.hide ? options.labels.stick : options.labels.unstick,
        "css": {
          "cursor": "pointer",
          "visibility": options.sticker_hover ? "hidden" : "visible"
        },
        "click": function(){
          notice.options.hide = !notice.options.hide;
          if (notice.options.hide) {
            notice.queueRemove();
          } else {
            notice.cancelRemove();
          }
          $(this).trigger("pnotify:buttons:toggleStick");
        }
      })
      .bind("pnotify:buttons:toggleStick", function(){
        var pin_up = that.options.classes.pin_up === null ? notice.styles.pin_up : that.options.classes.pin_up;
        var pin_down = that.options.classes.pin_down === null ? notice.styles.pin_down : that.options.classes.pin_down;
        $(this)
        .attr("title", notice.options.hide ? that.options.labels.stick : that.options.labels.unstick)
        .children()
        .attr("class", "")
        .addClass(notice.options.hide ? pin_up : pin_down)
        .attr("aria-pressed", notice.options.hide ? "false" : "true");
      })
      .append("<span />")
      .trigger("pnotify:buttons:toggleStick")
      .prependTo(notice.container);
      if (!options.sticker || (notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.sticker.css("display", "none");
      }

      // Provide a button to close the notice.
      this.closer = $("<div />", {
        "class": "ui-pnotify-closer",
        "aria-role": "button",
        "tabindex": "0",
        "title": options.labels.close,
        "css": {"cursor": "pointer", "visibility": options.closer_hover ? "hidden" : "visible"},
        "click": function(){
          notice.remove(false);
          that.sticker.css("visibility", "hidden");
          that.closer.css("visibility", "hidden");
        }
      })
      .append($("<span />", {"class": options.classes.closer === null ? notice.styles.closer : options.classes.closer}))
      .prependTo(notice.container);
      if (!options.closer || (notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.closer.css("display", "none");
      }
    },
    update: function(notice, options){
      // Update the sticker and closer buttons.
      if (!options.closer || (notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.closer.css("display", "none");
      } else if (options.closer) {
        this.closer.css("display", "block");
      }
      if (!options.sticker || (notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.sticker.css("display", "none");
      } else if (options.sticker) {
        this.sticker.css("display", "block");
      }
      // Update the sticker icon.
      this.sticker.trigger("pnotify:buttons:toggleStick");
      // Update the close icon.
      this.closer.find("span").attr("class", "").addClass(options.classes.closer === null ? notice.styles.closer : options.classes.closer);
      // Update the hover status of the buttons.
      if (options.sticker_hover) {
        this.sticker.css("visibility", "hidden");
      } else if (!(notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.sticker.css("visibility", "visible");
      }
      if (options.closer_hover) {
        this.closer.css("visibility", "hidden");
      } else if (!(notice.options.nonblock && notice.options.nonblock.nonblock && !options.show_on_nonblock)) {
        this.closer.css("visibility", "visible");
      }
    }
  };
  $.extend(PNotify.styling.brighttheme, {
    closer: "brighttheme-icon-closer",
    pin_up: "brighttheme-icon-sticker",
    pin_down: "brighttheme-icon-sticker brighttheme-icon-stuck"
  });
  $.extend(PNotify.styling.bootstrap3, {
    closer: "glyphicon glyphicon-remove",
    pin_up: "glyphicon glyphicon-pause",
    pin_down: "glyphicon glyphicon-play"
  });
  $.extend(PNotify.styling.fontawesome, {
    closer: "fa fa-times",
    pin_up: "fa fa-pause",
    pin_down: "fa fa-play"
  });
  return PNotify;
}));

// Desktop
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as a module.
    define('pnotify.desktop', ['jquery', 'pnotify'], factory);
  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
    // CommonJS
    module.exports = factory(require('jquery'), require('./pnotify'));
  } else {
    // Browser globals
    factory(root.jQuery, root.PNotify);
  }
}(typeof window !== "undefined" ? window : this, function($, PNotify){
  var permission;
  var notify = function(title, options){
    // Memoize based on feature detection.
    if ("Notification" in window) {
      notify = function (title, options) {
        return new Notification(title, options);
      };
    } else if ("mozNotification" in navigator) {
      notify = function (title, options) {
        // Gecko < 22
        return navigator.mozNotification
          .createNotification(title, options.body, options.icon)
          .show();
      };
    } else if ("webkitNotifications" in window) {
      notify = function (title, options) {
        return window.webkitNotifications.createNotification(
          options.icon,
          title,
          options.body
        );
      };
    } else {
      notify = function (title, options) {
        return null;
      };
    }
    return notify(title, options);
  };


  PNotify.prototype.options.desktop = {
    // Display the notification as a desktop notification.
    desktop: false,
    // If desktop notifications are not supported or allowed, fall back to a regular notice.
    fallback: true,
    // The URL of the icon to display. If false, no icon will show. If null, a default icon will show.
    icon: null,
    // Using a tag lets you update an existing notice, or keep from duplicating notices between tabs.
    // If you leave tag null, one will be generated, facilitating the "update" function.
    // see: http://www.w3.org/TR/notifications/#tags-example
    tag: null,
    // Optionally display a different title for the desktop.
    title: null,
    // Optionally display different text for the desktop.
    text: null
  };
  PNotify.prototype.modules.desktop = {
    genNotice: function(notice, options){
      if (options.icon === null) {
        this.icon = "http://sciactive.com/pnotify/includes/desktop/"+notice.options.type+".png";
      } else if (options.icon === false) {
        this.icon = null;
      } else {
        this.icon = options.icon;
      }
      if (this.tag === null || options.tag !== null) {
        this.tag = options.tag === null ? "PNotify-"+Math.round(Math.random() * 1000000) : options.tag;
      }
      notice.desktop = notify(options.title || notice.options.title, {
        icon: this.icon,
        body: options.text || notice.options.text,
        tag: this.tag
      });
      if (!("close" in notice.desktop) && ("cancel" in notice.desktop)) {
        notice.desktop.close = function(){
          notice.desktop.cancel();
        };
      }
      notice.desktop.onclick = function(){
        notice.elem.trigger("click");
      };
      notice.desktop.onclose = function(){
        if (notice.state !== "closing" && notice.state !== "closed") {
          notice.remove();
        }
      };
    },
    init: function(notice, options){
      if (!options.desktop)
        return;
      permission = PNotify.desktop.checkPermission();
      if (permission !== 0) {
        // Keep the notice from opening if fallback is false.
        if (!options.fallback) {
          notice.options.auto_display = false;
        }
        return;
      }
      this.genNotice(notice, options);
    },
    update: function(notice, options, oldOpts){
      if ((permission !== 0 && options.fallback) || !options.desktop)
        return;
      this.genNotice(notice, options);
    },
    beforeOpen: function(notice, options){
      if ((permission !== 0 && options.fallback) || !options.desktop)
        return;
      notice.elem.css({'left': '-10000px'}).removeClass('ui-pnotify-in');
    },
    afterOpen: function(notice, options){
      if ((permission !== 0 && options.fallback) || !options.desktop)
        return;
      notice.elem.css({'left': '-10000px'}).removeClass('ui-pnotify-in');
      if ("show" in notice.desktop) {
        notice.desktop.show();
      }
    },
    beforeClose: function(notice, options){
      if ((permission !== 0 && options.fallback) || !options.desktop)
        return;
      notice.elem.css({'left': '-10000px'}).removeClass('ui-pnotify-in');
    },
    afterClose: function(notice, options){
      if ((permission !== 0 && options.fallback) || !options.desktop)
        return;
      notice.elem.css({'left': '-10000px'}).removeClass('ui-pnotify-in');
      if ("close" in notice.desktop) {
        notice.desktop.close();
      }
    }
  };
  PNotify.desktop = {
    permission: function(){
      if (typeof Notification !== "undefined" && "requestPermission" in Notification) {
        Notification.requestPermission();
      } else if ("webkitNotifications" in window) {
        window.webkitNotifications.requestPermission();
      }
    },
    checkPermission: function(){
      if (typeof Notification !== "undefined" && "permission" in Notification) {
        return (Notification.permission === "granted" ? 0 : 1);
      } else if ("webkitNotifications" in window) {
        return window.webkitNotifications.checkPermission() == 0 ? 0 : 1;
      } else {
        return 1;
      }
    }
  };
  permission = PNotify.desktop.checkPermission();
  return PNotify;
}));

// Mobile
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as a module.
    define('pnotify.mobile', ['jquery', 'pnotify'], factory);
  } else if (typeof exports === 'object' && typeof module !== 'undefined') {
    // CommonJS
    module.exports = factory(require('jquery'), require('./pnotify'));
  } else {
    // Browser globals
    factory(root.jQuery, root.PNotify);
  }
}(typeof window !== "undefined" ? window : this, function($, PNotify){
  PNotify.prototype.options.mobile = {
    // Let the user swipe the notice away.
    swipe_dismiss: true,
    // Styles the notice to look good on mobile.
    styling: true
  };
  PNotify.prototype.modules.mobile = {
    init: function(notice, options){
      var that = this,
          origX = null,
          diffX = null,
          noticeWidth = null;

      this.swipe_dismiss = options.swipe_dismiss;
      this.doMobileStyling(notice, options);

      notice.elem.on({
        "touchstart": function(e){
          if (!that.swipe_dismiss) {
            return;
          }

          origX = e.originalEvent.touches[0].screenX;
          noticeWidth = notice.elem.width();
          notice.container.css("left", "0");
        },
        "touchmove": function(e){
          if (!origX || !that.swipe_dismiss) {
            return;
          }

          var curX = e.originalEvent.touches[0].screenX;

          diffX = curX - origX;
          var opacity = (1 - (Math.abs(diffX) / noticeWidth)) * notice.options.opacity;

          notice.elem.css("opacity", opacity);
          notice.container.css("left", diffX);
        },
        "touchend": function() {
          if (!origX || !that.swipe_dismiss) {
            return;
          }

          if (Math.abs(diffX) > 40) {
            var goLeft = (diffX < 0) ? noticeWidth * -2 : noticeWidth * 2;
            notice.elem.animate({"opacity": 0}, 100);
            notice.container.animate({"left": goLeft}, 100);
            notice.remove();
          } else {
            notice.elem.animate({"opacity": notice.options.opacity}, 100);
            notice.container.animate({"left": 0}, 100);
          }
          origX = null;
          diffX = null;
          noticeWidth = null;
        },
        "touchcancel": function(){
          if (!origX || !that.swipe_dismiss) {
            return;
          }

          notice.elem.animate({"opacity": notice.options.opacity}, 100);
          notice.container.animate({"left": 0}, 100);
          origX = null;
          diffX = null;
          noticeWidth = null;
        }
      });
    },
    update: function(notice, options){
      this.swipe_dismiss = options.swipe_dismiss;
      this.doMobileStyling(notice, options);
    },
    doMobileStyling: function(notice, options){
      if (options.styling) {
        notice.elem.addClass("ui-pnotify-mobile-able");

        if ($(window).width() <= 480) {
          if (!notice.options.stack.mobileOrigSpacing1) {
            notice.options.stack.mobileOrigSpacing1 = notice.options.stack.spacing1;
            notice.options.stack.mobileOrigSpacing2 = notice.options.stack.spacing2;
          }
          notice.options.stack.spacing1 = 0;
          notice.options.stack.spacing2 = 0;
        } else if (notice.options.stack.mobileOrigSpacing1 || notice.options.stack.mobileOrigSpacing2) {
          notice.options.stack.spacing1 = notice.options.stack.mobileOrigSpacing1;
          delete notice.options.stack.mobileOrigSpacing1;
          notice.options.stack.spacing2 = notice.options.stack.mobileOrigSpacing2;
          delete notice.options.stack.mobileOrigSpacing2;
        }
      } else {
        notice.elem.removeClass("ui-pnotify-mobile-able");

        if (notice.options.stack.mobileOrigSpacing1) {
          notice.options.stack.spacing1 = notice.options.stack.mobileOrigSpacing1;
          delete notice.options.stack.mobileOrigSpacing1;
        }
        if (notice.options.stack.mobileOrigSpacing2) {
          notice.options.stack.spacing2 = notice.options.stack.mobileOrigSpacing2;
          delete notice.options.stack.mobileOrigSpacing2;
        }
      }
    }
  };
  return PNotify;
}));

